package com.qyer.search.utils;/**
 * User: Z J Wu Date: 2016/02/23 Time: 14:29 Package: com.qyer.search.utils
 */

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.qyer.commons.exception.InvocationException;
import com.qyer.log.ContentShowLogger;
import com.qyer.log.PhraseShowLogger;
import com.qyer.log.WarningLogger;
import com.qyer.search.Constants;
import com.qyer.search.cache.mutable.MutableCaches;
import com.qyer.words.model.Impression;
import com.qyer.words.model.Word;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.configuration.CompositeConfiguration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.qyer.search.model.SearchParameterOrigin;

public class WordETLClient {

  private static final String CONTEXT = "rukawa-invocation";

  private static final Logger LOGGER = LoggerFactory.getLogger(WordETLClient.class);

  private static class InnerHolder {

    private static final WordETLClient INSTANCE = new WordETLClient();
  }

  public static WordETLClient getInstance() {
    return InnerHolder.INSTANCE;
  }

  private final Client client = ClientBuilder.newClient();
  private String SERVER_ROOT;
  private String QUERY_PATH;

  private WordETLClient() {
    CompositeConfiguration c = new CompositeConfiguration();
    try {
      c.addConfiguration(new PropertiesConfiguration("words_config.properties"));
      String host = c.getString("wordetl.restServerHost", "hanmeimei.qyer.com");
      int port = c.getInt("wordetl.restServerPort", 80);
      this.SERVER_ROOT = "http://" + host + ":" + port;
      this.QUERY_PATH = c.getString("wordetl.mainQueryPath", "translate");
      LOGGER.info("WordETL(Hanmeimei) - server-root - {}", this.SERVER_ROOT);
      LOGGER.info("WordETL(Hanmeimei) - query-path - {}", this.QUERY_PATH);
    } catch (ConfigurationException e) {
      LOGGER.error("Cannot load neo4j config.", e);
      return;
    }

    try {
      String serverStatus = getServerStatus();
      Map<String, Object> resultMap = JsonOperator.getInstance().fromJson(serverStatus, Map.class);
      if (MapUtils.isEmpty(resultMap)) {
        LOGGER.error("Result from {} is empty.", SERVER_ROOT);
      } else {
        for (Map.Entry<String, Object> entry : resultMap.entrySet()) {
          LOGGER.info("WordETL(Hanmeimei) - ping - {}({})", entry.getKey(), entry.getValue());
        }
      }
    } catch (Exception e) {
      LOGGER.error("Cannot get server status.", e);
    }
  }

  private void closeQuietly(Response response) {
    if (response != null) {
      response.close();
    }
  }

  public String getServerStatus() throws InvocationException {
    Response response = null;
    WebTarget target = client.target(SERVER_ROOT).path("/");
    try {
      response = target.request().accept(MediaType.APPLICATION_JSON_TYPE).get();
      int responseCode = response.getStatus();
      if (responseCode != 200) {
        throw new InvocationException("Return code is not 200.It is "+ responseCode);
      }
      return response.readEntity(String.class);
    } finally {
      closeQuietly(response);
    }
  }

  public Set<List<Word>> getBasicWord(final String userInputKW) throws InvocationException {
    Response response = null;
    String stringResult;
    WebTarget target = client.target(SERVER_ROOT).path(QUERY_PATH).queryParam("word", userInputKW)
                             .queryParam("context", CONTEXT);
    try {
      response = target.request().accept(MediaType.APPLICATION_JSON_TYPE).get();
      int responseCode = response.getStatus();
      if (responseCode != 200) {
        throw new InvocationException("Return code is not 200.");
      }
      stringResult = response.readEntity(String.class);
    } finally {
      closeQuietly(response);
    }
    if (StringUtils.isBlank(stringResult)) {
      throw new InvocationException("Cannot get any response content.");
    }
    Map<String, Object> resultMap;
    Map<String, List<List<Map<String, Object>>>> data;
    List<List<Map<String, Object>>> content;
    try {
      resultMap = JsonOperator.getInstance().fromJson(stringResult, Map.class);
    } catch (IOException e) {
      throw new InvocationException("Cannot read response value.", e);
    }
    if (MapUtils.isEmpty(resultMap)) {
      return null;
    }
    int status = (int) resultMap.get("status");
    if (status > 0) {
      String msg = (String) resultMap.get("msg");
      throw new InvocationException("Error " + status + ", Cannot etl word - " + msg);
    }
    data = (Map) resultMap.get("data");
    if (MapUtils.isEmpty(data)) {
      return null;
    }
    content = data.get("content");
    if (CollectionUtils.isEmpty(content)) {
      return null;
    }
    Set<List<Word>> result = Sets.newHashSetWithExpectedSize(content.size());
    List<Word> tupleList;
    for (List<Map<String, Object>> tuples : content) {
      if (CollectionUtils.isEmpty(tuples)) {
        continue;
      }
      tupleList = Lists.newArrayListWithExpectedSize(tuples.size());
      for (Map<String, Object> wordMap : tuples) {
        tupleList.add(new Word(String.valueOf(wordMap.get("name"))));
      }
      result.add(tupleList);
    }
    return result;
  }

  public Set<List<Word>> getBasicWord(final String userInputKW, final String requestId) throws InvocationException {

    long t1 = System.currentTimeMillis();
    Response response = null;
    String stringResult;

    if(StringUtils.isBlank(userInputKW)){
      return new HashSet<>();
    }
    //国家，城市
    int size = userInputKW.length();
    if(size <= 5){

      if(MutableCaches.getInstance().CITIES.getCacheContent().containsKey(userInputKW)){

        Set<List<Word>> set = new HashSet<>();
        List<Word> list = new ArrayList<>();
        list.add(new Word(userInputKW,Impression.IMPRESSION_CITY));
        set.add(list);

        try {
          PhraseShowLogger.logSplitResult("search_cache", requestId, "search_cache", userInputKW, "IMPRESSION_CITY");
        } catch (Exception e) {
          LOGGER.warn("Cannot send report({})", e);
        }
        //System.out.println("WORD时间:"+(System.currentTimeMillis() - t1));
        return set;
      }else if(MutableCaches.getInstance().COUNTRIES.getCacheContent().containsKey(userInputKW)){
        Set<List<Word>> set = new HashSet<>();
        List<Word> list = new ArrayList<>();
        list.add(new Word(userInputKW,Impression.IMPRESSION_COUNTRY));
        set.add(list);

        try {
          PhraseShowLogger.logSplitResult("search_cache", requestId, "search_cache", userInputKW, "IMPRESSION_COUNTRY");
        } catch (Exception e) {
          LOGGER.warn("Cannot send report({})", e);
        }

        return set;
      //}else if(Constants.CONTINENT_MAP.containsKey(userInputKW)){
      }else if(MutableCaches.getInstance().CONTINENT_DICT.getCacheContent().getReverseDict().containsKey(
        userInputKW)){
        Set<List<Word>> set = new HashSet<>();
        List<Word> list = new ArrayList<>();
        list.add(new Word(userInputKW,Impression.IMPRESSION_CONTINENT));
        set.add(list);

        try {
          PhraseShowLogger.logSplitResult("search_cache", requestId, "search_cache", userInputKW, "IMPRESSION_CONTINENT");
        } catch (Exception e) {
          LOGGER.warn("Cannot send report({})", e);
        }

        return set;
      }
    }

    WebTarget target = client.target(SERVER_ROOT).path(QUERY_PATH).queryParam("word", userInputKW)
                             .queryParam("context", CONTEXT).queryParam("requestId", requestId);
    try {
      response = target.request().accept(MediaType.APPLICATION_JSON_TYPE).get();
      int responseCode = response.getStatus();
      if (responseCode != 200) {
        throw new InvocationException("Return code is not 200.The error code is " + responseCode +
                                        ".The phrase is " + response.getStatusInfo().getReasonPhrase() +
                                        ".reason is " + response.getStatusInfo().toString());
      }
      stringResult = response.readEntity(String.class);
    } finally {
      closeQuietly(response);
    }
    if (StringUtils.isBlank(stringResult)) {
      throw new InvocationException("Cannot get any response content.");
    }
    Map<String, Object> resultMap;
    Map<String, List<List<Map<String, Object>>>> data;
    List<List<Map<String, Object>>> content;
    String strategy;
    String etlRequestId;

    try {
      resultMap = JsonOperator.getInstance().fromJson(stringResult, Map.class);
    } catch (IOException e) {
      throw new InvocationException("Cannot read response value.", e);
    }
    if (MapUtils.isEmpty(resultMap)) {
      return null;
    }
    int status = (int) resultMap.get("status");

    if (status > 0) {
      String msg = (String) resultMap.get("msg");
      throw new InvocationException("Error " + status + ", Cannot etl word - " + msg);
    }

    data = (Map) resultMap.get("data");
    if (MapUtils.isEmpty(data)) {
      return null;
    }
    content = data.get("content");
    strategy = String.valueOf(data.get("strategy"));
    etlRequestId = String.valueOf(data.get("request_id"));

    if (CollectionUtils.isEmpty(content)) {
      //return null;
      throw new InvocationException("HMM return blank content");
    }

    Set<List<Word>> result = Sets.newHashSetWithExpectedSize(content.size());
    List<Word> tupleList;
    for (List<Map<String, Object>> tuples : content) {
      if (CollectionUtils.isEmpty(tuples)) {
        continue;
      }
      tupleList = Lists.newArrayListWithExpectedSize(tuples.size());
      for (Map<String, Object> wordMap : tuples) {
        String type = String.valueOf(wordMap.get("type"));
        String name = String.valueOf(wordMap.get("name"));
        Word word = new Word(name, getImpression(type));
        tupleList.add(word);

        try {
          PhraseShowLogger.logSplitResult(etlRequestId, requestId, strategy, name, type);
        } catch (Exception e) {
          LOGGER.warn("Cannot send report({})", e);
        }

      }
      result.add(tupleList);
    }
    return result;
  }

  public static Impression getImpression(String s){
    if("IMPRESSION_CITY".equals(s) || "tag_city".equals(s))
      return Impression.IMPRESSION_CITY;
    else if("IMPRESSION_COUNTRY".equals(s) || "tag_country".equals(s)){
      return Impression.IMPRESSION_COUNTRY;
    }else if("IMPRESSION_POI".equals(s) || "tag_poi".equals(s)){
      return Impression.IMPRESSION_POI;
    }else if("tag_dict".equals(s) || "IMPRESSION_DICT".equals(s)){
      return Impression.IMPRESSION_DICT;
    }else if("TAGS".equals(s) || "tags".equals(s)){
      return Impression.TAGS;
    }else {
      return Impression.UNKNOWN;
    }
  }
  public static void main(String[] args) throws InvocationException {
    WordETLClient client = WordETLClient.getInstance();
    System.out.println(client.getBasicWord(""));
    //System.out.println(Impression.parseImpression("tags"));
    //System.out.println(Impression.IMPRESSION_CITY.name());
    //System.out.println(getImpression("TAGS"));
  }
}
